﻿using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using GurLoader;
using GurLoader.CommandLineOptions;
using GurLoader.Preferences;
using GurLoader.Service;
using GurLoader.Service.ImgurTaskBuilder;
using GurLoader.Service.MessageProcessing;
using Imgur.Net;
using Moq;
using NUnit.Framework;

namespace GurLoaderWPF.Test.Service.MessageProcessing
{
    [TestFixture]
    public class MailslotMessageServiceTest
    {
        [Test]
        public void CreateInstanceTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Assert.IsNotNull(messageService);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullExecutionServiceTest()
        {
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(null, mockDispatcher.Object, preferences);

            Assert.IsNotNull(messageService);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullDispatcherTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, null, preferences);

            Assert.IsNotNull(messageService);
        }

        [Test]
        public void SendAlbumValidParamsTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = CreateTempImage();
            string imgFile2 = CreateTempImage();

            string command = string.Format("{0} -t \"{3}\" -d \"{4}\" -l {5} \"{1}\" \"{2}\"",
                Command.SendAlbum, imgFile1, imgFile2, "My Title", "My Description", LayoutStyle.Grid);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        private string CreateTempImage()
        {
            string tempFileName = Path.GetTempFileName();
            Bitmap bmp = new Bitmap(20,20);
            for( int x = 0; x < bmp.Width; x++ )
                for (int y = 0; y < bmp.Height; y++ )
                    bmp.SetPixel(x, y, Color.Aqua );

            bmp.Save(tempFileName);

            return tempFileName;
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException))]
        public void SendAlbumNoImagesTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = CreateTempImage();
            string imgFile2 = CreateTempImage();

            string command = string.Format("{0} -t \"{1}\" -d \"{2}\" -l {3}",
                Command.SendAlbum, "My Title", "My Description", LayoutStyle.Grid);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        [Test]
        public void SendAlbumWithSomeInvalidImagesTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = CreateTempImage();
            string imgFile2 = "blahbadfilename";

            string command = string.Format("{0} -t \"{3}\" -d \"{4}\" -l {5} \"{1}\" \"{2}\"",
                Command.SendAlbum, imgFile1, imgFile2, "My Title", "My Description", LayoutStyle.Grid);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException), ExpectedMessage = "Unable to find any valid files as part of command line.")]
        public void SendAlbumWithNoInvalidImagesTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = "blahbadfilename";
            string imgFile2 = "blahbadfilename";

            string command = string.Format("{0} -t \"{3}\" -d \"{4}\" -l {5} \"{1}\" \"{2}\"",
                Command.SendAlbum, imgFile1, imgFile2, "My Title", "My Description", LayoutStyle.Grid);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException))]
        public void ProcessMessageNoActionTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                string.Empty, mockProgress.Object, ct);
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException))]
        public void ProcessMessageUndefinedActionTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            string command = string.Format("{0} {1} {2}", "RandomActionName", string.Empty, string.Empty);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException))]
        public void ProcessMessageUnknownActionTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            string command = string.Format("{0} {1} {2}", "Unknown", string.Empty, string.Empty);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);
        }

        [Test]
        [ExpectedException(typeof(CommandLineParsingException), ExpectedMessage = "Unable to find any valid files as part of command line.")]
        public void SendImagesWithNoValidImagesTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = "badfilename";
            string imgFile2 = "otherbadfilename";

            string command = string.Format("{0} \"{1}\" \"{2}\"",
                Command.SendImages, imgFile1, imgFile2);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        [Test]
        public void SendImagesWithSomeInvalidImagesTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = CreateTempImage();
            string imgFile2 = "badfilename";

            string command = string.Format("{0} \"{1}\" \"{2}\"",
                Command.SendImages, imgFile1, imgFile2);

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }

        [Test]
        public void SendImagesValidParamsTest()
        {
            Mock<ITaskBuilderService> mockExecutionService = new Mock<ITaskBuilderService>();
            Mock<IProgress<IDelegatingCommandProgress>> mockProgress = new Mock<IProgress<IDelegatingCommandProgress>>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            GurLoaderPreferences preferences = new GurLoaderPreferences();

            // CT is a struct so can not mock (requires reference type)
            CancellationToken ct = new CancellationTokenSource().Token;

            // create 2 temp image files
            string imgFile1 = CreateTempImage();
            string imgFile2 = CreateTempImage();

            string command = string.Format("{0} \"{1}\" \"{2}\"",
                Command.SendImages, imgFile1, imgFile2 );

            MailslotMessageProcessingService messageService = new MailslotMessageProcessingService(mockExecutionService.Object, mockDispatcher.Object, preferences);

            Task<ImgurProcessResult> resultTask = messageService.ProcessMessage<ImgurProcessResult>(
                command, mockProgress.Object, ct);

            Assert.IsNotNull(resultTask);
        }



    }
}
